package cc.loac.heba.service;

import cc.loac.heba.dao.UserDao;
import cc.loac.heba.pojo.*;
import cc.loac.heba.tool.Common;
import cc.loac.heba.tool.MyCOSClient;
import com.alibaba.fastjson.JSONObject;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;

@Service
public class UserService {

    @Resource
    UserDao userDao;

    @Resource
    CheckCodeService checkCodeService;

    @Resource
    LoginTokenService loginTokenService;

    @Resource
    MessageService messageService;

    /**
     * 登录
     * @param email 邮箱
     * @param password md5 密码
     * @return Result
     */
    public String login(String email, String password) {
        User user;
        Result result = new Result();
        try {
            // 根据邮箱和密码获取 User
            user = getUserByEmailAndPassword(email, password);
            if (user == null) {
                result.setMessage("邮箱或密码错误");
                result.setStatus(-2);
            } else {
                // 登录成功
                String loginToken = loginTokenService.createLoginToken(email);
                // 更新最后登录时间
                Date currentDate = new Date();
                user.setLastLoginTime(currentDate);
                updateLastLoginTime(email, currentDate);

                // 将 User 实体类格式化为 JSON
                JSONObject json = JSONObject.parseObject(JSONObject.toJSONString(user));
                // 将 Token 加入 JSON
                json.put("token", loginToken);
                result.setContent(json);
            }
        } catch (Exception e) {
            e.printStackTrace();
            result = Common.exceptionResult();
        }
        return Common.toJson(result);
    }

    /**
     * 注册用户
     * @param email 邮箱
     * @param username 用户名
     * @param password md5 密码
     * @param checkCode 验证码
     * @return Result
     */
    public String register(String email, String username, String password, String checkCode) {
        Result result = new Result();
        try {
            // 判断邮箱是否已经存在
            if (getUserCountByEmail(email) >= 1) {
                result.setMessage("邮箱已经存在");
                result.setStatus(-2);
                return Common.toJson(result);
            }

            // 判断验证码是否正确
            Result checkCodeResult = checkCodeService.checkCode(email, checkCode, CheckCode.TYPE_REGISTER);
            if (checkCodeResult.getStatus() != 0) {
                // 验证码不正确，返回错误原因
                return Common.toJson(checkCodeResult);
            }

            // 创建用户
            int createResult = createUser(email, username, password);
            if (createResult > 0) {
                result.setStatus(0);
                result.setMessage("OK");
                result.setContent(getUserByEmail(email));
            } else {
                result.setStatus(-2);
                result.setMessage("创建用户失败，请稍后重试");
            }
            return Common.toJson(result);
        } catch (Exception e) {
            e.printStackTrace();
            return Common.exceptionResults();
        }
    }

    /**
     * 忘记密码修改密码
     * @param email 邮箱
     * @param password 新 md5 密码
     * @param checkCode 验证码
     * @return Result
     */
    public String forget(String email, String password, String checkCode) {
        Result result = new Result();
        try {
            // 判断邮箱是否存在
            if (getUserCountByEmail(email) == 0) {
                result.setMessage("邮箱不存在，请注册");
                result.setStatus(-2);
                return Common.toJson(result);
            }

            // 判断验证码是否正确
            Result checkCodeResult = checkCodeService.checkCode(email, checkCode, CheckCode.TYPE_FORGET_PASSWORD);
            if (checkCodeResult.getStatus() != 0) {
                // 验证码不正确，返回错误原因
                return Common.toJson(checkCodeResult);
            }

            // 修改密码
            int updateResult = updatePasswordByEmail(email, password);
            if (updateResult > 0) {
                result.setStatus(0);
                result.setMessage("OK");
            } else {
                result.setStatus(-2);
                result.setMessage("修改密码失败，请稍后重试");
            }
            return Common.toJson(result);
        } catch (Exception e) {
            e.printStackTrace();
            return Common.exceptionResults();
        }
    }


    /**
     * 添加用户
     * @param email 邮箱
     * @param username 用户名
     * @param password md5 密码
     * @return 改动行数
     */
    public int createUser(String email, String username, String password) {
        int result;
        try {
            result = userDao.insertUser(email, username, password, new Date());
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            return -1;
        }
    }

    /**
     * 根据邮箱和密码获取 User
     * @param email 邮箱
     * @param password 密码
     * @return User
     */
    public User getUserByEmailAndPassword(String email, String password) {
        User user;
        try {
            user = userDao.selectUserByEmailAndPassword(email, password);
            return user;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 根据邮箱获取 User
     * @param email 邮箱
     * @return User
     */
    public User getUserByEmail(String email) {
        User user;
        try {
            user = userDao.selectUserByEmail(email);
            return user;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 根据邮箱获取用户数量
     * @param email 邮箱
     * @return 用户数量
     */
    public int getUserCountByEmail(String email) {
        int count;
        try {
            count = userDao.selectUserCountByEmail(email);
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return -1;
        }
    }

    /**
     * 根据邮箱修改密码
     * @param email 邮箱
     * @param password md5 密码
     * @return 改变条数
     */
    public int updatePasswordByEmail(String email, String password) {
        int result;
        try {
            result = userDao.updatePasswordByEmail(email, password);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            return -1;
        }
    }

    /**
     * 根据邮箱和时间修改最后登录时间
     * @param email 邮箱
     * @param date 时间
     */
    public void updateLastLoginTime(String email, Date date) {
        try {
            userDao.updateLastLoginTime(email, date);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取我的个人信息
     * @param email 邮箱
     * @param token 登录令牌
     * @return Result
     */
    public String getMyInfo(String email, String token) {
        Result result;
        try {
            result = tokenIsExpired(email, token);
            if (result.getStatus() != 0) {
                // Token 有问题，返回原因
                return Common.toJson(result);
            }
            // 获取个人信息
            User user = userDao.selectUserByEmail(email);
            result.setContent(user);
            return Common.toJson(result);
        } catch (Exception e) {
            e.printStackTrace();
            return Common.exceptionResults();
        }
    }

    /**
     * 获取他人信息
     * @param email 自己邮箱
     * @param userEmail 要查询的用户邮箱
     * @param token Token
     * @return Result
     */
    public String getInfoByEmail(String email, String userEmail, String token) {
        Result result;
        try {
            result = tokenIsExpired(email, token);
            if (result.getStatus() != 0) {
                // Token 有问题，返回原因
                return Common.toJson(result);
            }
            User user = userDao.selectUserByEmail(userEmail);
            if (user == null) {
                result.setMessage("用户不存在");
                result.setStatus(-2);
                return Common.toJson(result);
            }
            // 获取他人信息需屏蔽部分信息
            user.setCreateTime(null);
            user.setLastLoginTime(null);
            user.setBirthDay(null);
            user.setEmail("");
            result.setContent(user);
            return Common.toJson(result);
        } catch (Exception e) {
            e.printStackTrace();
            return Common.exceptionResults();
        }
    }

    /**
     * 根据邮箱更新 Profile
     * @param email 邮箱
     * @param profile 简介
     * @param token token
     * @return Result
     */
    public String updateProfileByEmail(String email, String profile, String token) {
        Result result;
        try {
            result = tokenIsExpired(email, token);
            if (result.getStatus() != 0) {
                // Token 有问题，返回原因
                return Common.toJson(result);
            }
            // 更新 Profile
            int updateResult = userDao.updateProfileByEmail(email, profile);
            if (updateResult <= 0) {
                result.setMessage("更新简介失败，请稍后重试");
                result.setStatus(-2);
                return Common.toJson(result);
            }
            return Common.toJson(result);
        } catch (Exception e) {
            e.printStackTrace();
            return Common.exceptionResults();
        }
    }

    /**
     * 上传头像
     * @param email 邮箱
     * @param file 头像文件
     * @param token Token
     * @return Result Content 内容为头像地址
     */
    public String uploadAvatar(String email, MultipartFile file, String token) {
        Result result;
        try {
            result = tokenIsExpired(email, token);
            if (result.getStatus() != 0) {
                // Token 有问题，返回原因
                return Common.toJson(result);
            }

            if (file == null || file.isEmpty()) {
                result.setStatus(-2);
                result.setMessage("上传的头像文件为空");
                return Common.toJson(result);
            }

            // 上传的图像原始文件名
            String fileName = file.getOriginalFilename();
            // 获取文件类型（后缀名）
            assert fileName != null;
            String fileType = fileName.substring(fileName.lastIndexOf("."));
            String newFileName = UUID.randomUUID() + fileType;

            // 上传头像
            File localFile = File.createTempFile("temp", null);
            file.transferTo(localFile);
            String newAvatarUrl = MyCOSClient.uploadImage(localFile, email + "/" + newFileName);

            // 上传成功，设置 Result 的 Content 为新头像的地址
            result.setContent(newAvatarUrl);

            // 单独开一个线程去修改数据库以及删除旧头像文件
            new Thread(() -> updateAvatarByEmailAndNewUrl(email, newAvatarUrl)).start();
            return Common.toJson(result);
        } catch (Exception e) {
            e.printStackTrace();
            result = new Result();
            result.setMessage("上传头像失败");
            result.setStatus(-2);
            return Common.toJson(result);
        }
    }


    /**
     * 检查 Token 是否不存在或者过期
     * @param email 邮箱
     * @param token Token
     * @return Result
     */
    private Result tokenIsExpired(String email, String token) {
        // 未传入 token
        if (token == null) {
            return Common.tokenIsNull();
        }
        Result tokenResult = loginTokenService.checkToken(email, token);
        if (tokenResult.getStatus() != 0) {
            // Token 已经过期
            return tokenResult;
        }
        return new Result();
    }

    /**
     * 根据邮箱和新头像地址更新用户头像，同时删除旧头像文件
     * @param email 邮箱
     * @param newAvatarUrl 新头像地址
     */
    private void updateAvatarByEmailAndNewUrl(String email, String newAvatarUrl) {
        try {
            // 先删除旧头像文件
            User user = getUserByEmail(email);
            if (user.getAvatar() != null && !user.getAvatar().equals("")){
                // 旧头像存在，获取在腾讯云存储库中的地址。（获取 Heba 文件夹后的地址）
                String oldAvatarUrl = Common.getIntermediateText(user.getAvatar(), "/Heba/", "");
                // 删除旧头像文件
                if (!oldAvatarUrl.equals("")) {
                    MyCOSClient.deleteFile(oldAvatarUrl);
                }
            }

            // 将新头像地址存入数据库
            userDao.updateAvatarByEmailAndNewUrl(email, newAvatarUrl);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据邮箱添加用户喜欢数量
     * @param email 邮箱
     */
    public void addUserLikesByEmail(String email) {
        try {
            userDao.updateLikesAdd(email);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据邮箱添加用户收藏数量
     * @param email 邮箱
     */
    public void addUserCollectionsByEmail(String email) {
        try {
            userDao.updateCollectionsAdd(email);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据邮箱删除用户喜欢数量
     * @param email 邮箱
     */
    public void deleteUserLikesByEmail(String email) {
        try {
            userDao.updateLikesMinus(email);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 根据邮箱删除用户收藏数量
     * @param email 邮箱
     */
    public void deleteUserCollectionsByEmail(String email) {
        try {
            userDao.updateCollectionsMinus(email);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 更新用户资料
     * @param email 邮箱
     * @param username 用户名
     * @param gender 性别
     * @param birth 生日
     * @param school 学校
     * @param token Token
     * @return Result
     */
    public String updateUser(String email, String username, String gender, String birth, String school, String token) {
        Result result;
        try {
            result = tokenIsExpired(email, token);
            if (result.getStatus() != 0) {
                // Token 有问题，返回原因
                return Common.toJson(result);
            }
            userDao.updateUser(email, username, gender, birth, school);
            return Common.toJson(result);
        } catch (Exception e) {
            e.printStackTrace();
            return Common.exceptionResults();
        }
    }

    /**
     * 添加关注
     * @param email 自己邮箱
     * @param followEmail 关注者邮箱
     * @param token Token
     * @return Result
     */
    public String addFollow(String email, String followEmail, String token) {
        Result result;
        try {
            result = tokenIsExpired(email, token);
            if (result.getStatus() != 0) {
                // Token 有问题，返回原因
                return Common.toJson(result);
            }

            // 首先判断是否已经关注
            UserRelation userRelation = userDao.selectRelationByEmailAndFollowEmail(email, followEmail);
            if (userRelation != null) {
                // 已经关注，直接返回 OK
                return Common.toJson(result);
            }

            // 插入用户关系
            userDao.insertFollow(email, followEmail, new Date());

            // 单独的线程发送消息
            new Thread(() -> {
                // 刷新被关注者粉丝数量
                updateFansByEmail(followEmail);

                // 刷新关注者关注数量
                updateFollowsByEmail(email);

                // 给被关注者发送消息
                messageService.addMessage(email, followEmail, Message.TYPE_FOLLOW, null);
            }).start();
            return Common.toJson(result);
        } catch (Exception e) {
            e.printStackTrace();
            return Common.exceptionResults();
        }
    }

    /**
     * 刷新用户关注数量
     * @param email 邮箱
     */
    private void updateFollowsByEmail(String email) {
        try {
            // 获取用户关注数量
            int count = getUserFollowCountByEmail(email);

            // 修改用户关注数量
            userDao.updateUserFollowCount(email ,count);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取用户关注数量
     * @param email 邮箱
     * @return 关注数量
     */
    private int getUserFollowCountByEmail(String email) {
        try {
            return userDao.selectUserFollowCountByEmail(email);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 刷新用户粉丝数量
     * @param email 邮箱
     */
    private void updateFansByEmail(String email) {
        try {
            // 获取用户粉丝数量
            int count = getUserFanCountByEmail(email);

            // 修改用户关注数量
            userDao.updateUserFanCount(email ,count);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取用户粉丝数量
     * @param email 邮箱
     * @return 粉丝数量
     */
    private int getUserFanCountByEmail(String email) {
        try {
            return userDao.selectUserFanCountByEmail(email);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 删除关注
     * @param email 自己邮箱
     * @param followEmail 关注者邮箱
     * @param token Token
     * @return Result
     */
    public String deleteFollow(String email, String followEmail, String token) {
        Result result;
        try {
            result = tokenIsExpired(email, token);
            if (result.getStatus() != 0) {
                // Token 有问题，返回原因
                return Common.toJson(result);
            }
            userDao.deleteFollow(email, followEmail);

            // 单独线程处理其他数据
            new Thread(() -> {
                // 刷新被关注者粉丝数量
                updateFansByEmail(followEmail);

                // 刷新关注者粉丝数量
                updateFollowsByEmail(email);
            }).start();
            return Common.toJson(result);
        } catch (Exception e) {
            e.printStackTrace();
            return Common.exceptionResults();
        }
    }

    /**
     * 获取关注的用户
     * @param email 邮箱
     * @param token Token
     * @return Result
     */
    public String getFollow(String email, String token) {
        Result result;
        try {
            result = tokenIsExpired(email, token);
            if (result.getStatus() != 0) {
                // Token 有问题，返回原因
                return Common.toJson(result);
            }

            // 获取关注的用户 (UserRelation)
            List<UserRelation> userRelations = userDao.selectFollow(email);
            if (userRelations == null || userRelations.size() == 0) {
                result.setContent(new ArrayList<>());
                return Common.toJson(result);
            }

            // 根据用户邮箱数组获取用户数组
            List<String> emails = new ArrayList<>();
            for (UserRelation userRelation : userRelations) {
                emails.add(userRelation.getFollowEmail());
            }

            List<User> users = getUserByEmails(emails, true);
            result.setContent(users);
            return Common.toJson(result);
        } catch (Exception e) {
            e.printStackTrace();
            return Common.exceptionResults();
        }
    }

    /**
     * 获取粉丝
     * @param email 邮箱
     * @param token Token
     * @return Result
     */
    public String getFan(String email, String token) {
        Result result;
        try {
            result = tokenIsExpired(email, token);
            if (result.getStatus() != 0) {
                // Token 有问题，返回原因
                return Common.toJson(result);
            }
            // 获取粉丝 (UserRelation)
            List<UserRelation> userRelations = userDao.selectFan(email);
            if (userRelations == null || userRelations.size() == 0) {
                result.setContent(new ArrayList<>());
                return Common.toJson(result);
            }

            // 根据用户邮箱数组获取用户数组
            List<String> emails = new ArrayList<>();
            for (UserRelation userRelation : userRelations) {
                emails.add(userRelation.getEmail());
            }

            List<User> users = getUserByEmails(emails, true);
            result.setContent(users);
            return Common.toJson(result);
        } catch (Exception e) {
            e.printStackTrace();
            return Common.exceptionResults();
        }
    }


    /**
     * 根据邮箱数组获取用户
     * @param emails 邮箱数组
     * @param hide 是否隐藏敏感数据
     * @return List<User>
     */
    private List<User> getUserByEmails(List<String> emails, boolean hide) {
        if (emails == null || emails.size() == 0) {
            return new ArrayList<>();
        }
        List<User> users;
        try {
            users = userDao.selectUserByEmails(emails);
            if (users != null && users.size() != 0 && hide) {
                for (int i = 0; i < users.size(); i++) {
                    User user = users.get(i);
                    user.setCreateTime(null);
                    user.setLastLoginTime(null);
                    users.set(i, user);
                }
            }
            return users;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 判断是否已经关注当前用户
     * @param email 关注者的邮箱
     * @param followEmail 被关注者的邮箱
     * @param token Token
     * @return Result
     */
    public String isFollow(String email, String followEmail, String token) {
        Result result;
        JSONObject jsonObject = new JSONObject();
        try {
            result = tokenIsExpired(email, token);
            if (result.getStatus() != 0) {
                // Token 有问题，返回原因
                return Common.toJson(result);
            }
            UserRelation userRelation = userDao.selectRelationByEmailAndFollowEmail(email, followEmail);
            if (userRelation == null) {
                jsonObject.put("isFollow", false);
            } else {
                jsonObject.put("isFollow", true);
            }

            result.setContent(jsonObject);
            return Common.toJson(result);
        } catch (Exception e) {
            e.printStackTrace();
            return Common.exceptionResults();
        }
    }
}
